
import sys
from can_matrix import *


[TS, SECS, ID, RTX, T, LEN, V0, V1, V2, V3, V4, V5, V6, V7] = range(0, 14)

class CANCmd:
    def __init__(self, vals):
        self.ts = float(vals[TS])
        self.secs = int(vals[SECS])
        self.id = int(vals[ID], 16)
        self.rtx = vals[RTX]
        self.len = int(vals[LEN])
        self.vals = []
        self.vals.append(int(vals[V0], 16))
        self.vals.append(int(vals[V1], 16))
        self.vals.append(int(vals[V2], 16))
        self.vals.append(int(vals[V3], 16))
        self.vals.append(int(vals[V4], 16))
        self.vals.append(int(vals[V5], 16))
        self.vals.append(int(vals[V6], 16))
        self.vals.append(int(vals[V7], 16))
        self.val = long('%s%s%s%s%s%s%s%s' % (vals[V0], vals[V1], vals[V2], vals[V3], vals[V4], vals[V5], vals[V6], vals[V7]), 16)
        self.valStr = '{0:0>64b}'.format(self.val)

    def toString(self):
        return '\"%8.6f\", \"%4x\", \"%016x\", ' % (self.ts, self.id, self.val)
        
    def getIntVal(self, start, end):
        '''Return the integer value of [start:end] bit position.
        @warning, (fixme) can't get the cross bytes value now.
        '''
        idx = int(start/8)
        mask = (1 << (end - start + 1)) - 1
        shf = start % 8
        return (self.vals[idx] >> shf) & mask

class Canius:
    '''CAN matrix definition columns'''
    [   ID,         MSB,    LSB,    SIZE,   TRANS,  RECV,       DESC,       NAME,           ] = range(0, 8)

    def __init__(self):
        self.defn = {}

        for cmd in CAN_MATRIX_DEFN:
            if cmd[Canius.ID] not in self.defn.keys():
                self.defn[cmd[Canius.ID]] = {}
                self.defn[cmd[Canius.ID]][Canius.TRANS] = cmd[Canius.TRANS].replace(',', ';')
                self.defn[cmd[Canius.ID]][Canius.RECV]  = cmd[Canius.RECV].replace(',', ';')
                self.defn[cmd[Canius.ID]][Canius.NAME]  = cmd[Canius.NAME].replace(',', ';')
                self.defn[cmd[Canius.ID]][Canius.ID]    = cmd[Canius.ID]
                self.defn[cmd[Canius.ID]][Canius.DESC]  = []
            self.defn[cmd[Canius.ID]][Canius.DESC].append([cmd[Canius.DESC], cmd[Canius.MSB], cmd[Canius.LSB]])

    def format(self, cmd):
        if cmd.id in self.defn.keys():
            fmtStr = '\"%x:%s\", \"%s\", \"%s\", \"' % (self.defn[cmd.id][Canius.ID], self.defn[cmd.id][Canius.NAME], self.defn[cmd.id][Canius.TRANS], self.defn[cmd.id][Canius.RECV])
            for defn in self.defn[cmd.id][Canius.DESC]:
                fmtStr += '%s: %d; ' % (defn[0], cmd.getIntVal(defn[2], defn[1]))
            fmtStr += '\"'
        else:
            fmtStr = ''
        return fmtStr

    def analyzeCmd(self, line):
        vals = line.split()

        print '\"%s\", ' % line.rstrip('\r').rstrip('\n'),
        if vals[ID] in CAN_ID_FILTER:
            cmd = CANCmd(vals)
            print cmd.toString(),
            print self.format(cmd)
        else:
            print ',,,,,,'

    def analyze(self, fileName):
        print 'Tring to analyze [%s]' % fileName

        print 'log, ts, id, val, name, trans, recv, values'
        with open(fileName) as canLog:
            while True:
                line = canLog.readline()
                if line:
                    self.analyzeCmd(line)
                else:
                    break

def test(fileName):
    with open(fileName) as canLog:
        defn = Canius()
        
        while True:
            line = canLog.readline()
            if line:
                defn.analyzeCmd(line)
            else:
                break

def usage():
    print 'canius.py can_log_file_name > xxx.csv'

if __name__ == '__main__':

    if len(sys.argv) > 1:
        canius = Canius()
        canius.analyze(sys.argv[1])
    else:
        usage()


